/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.elcom.dailyinfo.smscbclient.httpclient;

import com.elcom.dailyinfo.smscbclient.cbcrequest.BaseMessageRequest;
import com.elcom.dailyinfo.smscbclient.cbcrequest.CbcRequest;
import com.elcom.dailyinfo.smscbclient.cbcrequest.GetBscCellsRequest;
import com.elcom.dailyinfo.smscbclient.cbcrequest.GetBscsRequest;
import com.elcom.dailyinfo.smscbclient.cbcrequest.SendMessageRequest;
import com.elcom.dailyinfo.smscbclient.cbcrequest.UpdateMessageRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author GiangLT
 */
public class SmscbHttpClient {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private static SmscbHttpClient instance;
    private HttpClient httpClient;
    private ResponseHandler<String> responseHandler;
    private HttpGet httpGet;
    private String uri;
    private AtomicBoolean isConnected = new AtomicBoolean(false);

    private SmscbHttpClient(String uri) {
        this.uri = uri;
    }

    public static synchronized SmscbHttpClient getInstance(String uri) {
        if (instance == null) {
            instance = new SmscbHttpClient(uri);
        }
        return instance;
    }

    public final synchronized void connect() {
        if (!isConnected.get()) {
            logger.warn("Initiating HTTP connection to {}", uri);
            httpClient = new DefaultHttpClient();
            ClientConnectionManager mgr = httpClient.getConnectionManager();
            HttpParams params = httpClient.getParams();
            HttpConnectionParams.setConnectionTimeout(params, 5000);
            HttpConnectionParams.setSoTimeout(params, 5000);
            httpClient = new DefaultHttpClient(new PoolingClientConnectionManager(mgr.getSchemeRegistry()), params);

            responseHandler = new StringResponseHandler();
            try {
                URI URI = new URI(uri);
                httpGet = new HttpGet(URI);
                isConnected.set(true);
                logger.warn("Initiated HTTP connection to {}", uri);
            } catch (URISyntaxException ex) {
                logger.error("URI syntax error: {}", uri, ex);
            }
        } else {
            logger.debug("Already connected to {}", uri);
        }
    }

    public synchronized String send(CbcRequest command) throws Exception {
        if (!isConnected.get()) {
            connect();
        }
        URI parameterizedUri = buildUri(command);
        httpGet.setURI(parameterizedUri);

        logger.info("==> Sending HttpRequest to [{}]: {}", httpGet.getURI().toString(), command);
        return httpClient.execute(httpGet, responseHandler);
    }

    private URI buildUri(CbcRequest command) throws URISyntaxException {
        URIBuilder uriBuilder = new URIBuilder(uri);
        uriBuilder.setParameter("fn", command.getFunctionName());
        uriBuilder.setParameter("un", command.getUsername());
        uriBuilder.setParameter("p", command.getPassword());

        if (command instanceof SendMessageRequest) {
            SendMessageRequest sendMessage = (SendMessageRequest) command;
            uriBuilder.setParameter("duration", String.valueOf(sendMessage.getDuration()));
            uriBuilder.setParameter("bsclist", sendMessage.getBscList());
            uriBuilder.setParameter("celllist", sendMessage.getCellList());
            uriBuilder.setParameter("data", sendMessage.getData());
            uriBuilder.setParameter("dcs", sendMessage.getDcs());
            uriBuilder.setParameter("encoding", sendMessage.getEncoding());
            uriBuilder.setParameter("messageidentifier", sendMessage.getMessageId());
            uriBuilder.setParameter("repetitionrate", String.valueOf(sendMessage.getRepetitionRate()));
            uriBuilder.setParameter("waittobroadcast", String.valueOf(sendMessage.getWaitToBroadcast()));
        } else if (command instanceof GetBscCellsRequest) {
            GetBscCellsRequest getBscCells = (GetBscCellsRequest) command;
            uriBuilder.setParameter("bscid", getBscCells.getBscId());
        } else if (!(command instanceof GetBscsRequest)) {
            BaseMessageRequest baseMessageRequest = (BaseMessageRequest) command;
            uriBuilder.setParameter("messageid", baseMessageRequest.getMessageId());
            if (baseMessageRequest instanceof UpdateMessageRequest) {
                UpdateMessageRequest updateMessageRequest = (UpdateMessageRequest) baseMessageRequest;
                uriBuilder.setParameter("data", updateMessageRequest.getData());
            }
        }

        return uriBuilder.build();
    }

    public synchronized void shutdownConnection() throws UnsupportedEncodingException, ClientProtocolException, IOException {
        if (isConnected.get() && httpClient != null) {
            logger.warn("Shuting down all connections to CBC");
//            unbind();
            httpClient.getConnectionManager().closeExpiredConnections();
            httpClient.getConnectionManager().closeIdleConnections(1, TimeUnit.MILLISECONDS);
            httpClient.getConnectionManager().shutdown();
            logger.warn("All connections to CBC were shutdown");
        }
    }

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }
}
